#!/usr/bin/env python
#
# - Main role of this file is to remove polling in tasktracker.
# - should be running when the tasktracker(mdserv.py) is launched.
# - recommend to use daemon mode.
# 		> nohup ./[this file's name] &
#
# @modified: June 17th, 2012
# @author: Yurong Jiang, Xing Xu, Moo-Ryong Ra
#
import time, os, copy, sys, random, threading, socket, select
import mdlib
import BaseHTTPServer, urlparse, cgi
from xml.etree import ElementTree as ET

HOSTNAME = 'localhost'
NPORT = 7667
CONN = {}

class MedTTCbHandler(BaseHTTPServer.BaseHTTPRequestHandler):
	#
	def do_HEAD(s):
		s.send_response(200)
		s.send_header("Content-type", "text/html")
		s.end_headers()
	#
	def do_POST(self):
		ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))

		if ctype == 'multipart/form-data':
			postvars = cgi.parse_multipart(self.rfile, pdict)
		elif ctype == 'application/x-www-form-urlencoded':
			length = int(self.headers.getheader('content-length'))
			postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
			process_file(postvars)
		else:
			postvars = {}

		self.send_response(200)
		self.send_header("Content-type", "text/html")
		self.end_headers()


class MedTTEventRelay(threading.Thread):
	#
	def run(self):
		global CONN

		soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		soc.bind(('localhost', 20968))
		soc.listen(5)

		while True:
			soc_input = [soc]
			for (k, v) in CONN.iteritems():
				soc_input.append(v)

			_in, _out, _exc = select.select(soc_input, [], [])

			for s in _in:
				if s == soc:
					(c, a) = soc.accept()
					pid = mdlib.msg_recv(c, 1024)
					CONN[str(pid)] = c

					mdlib.log("* pid registered: "+ pid)
				else:
					temp = s.recv(1024)
					if len(temp) == 0:
						mdlib.log('* closing socket') 
						s.close()

					for (k, v) in CONN.iteritems():
						if s == v:
							mdlib.log('* ' + str(k) + ' closed.')
							del CONN[k]
							break
					
def run_medscript(prognames):
	#
	global CONN, soc

	for i in prognames:
		newpid = os.fork()

		if newpid == 0:
			cmd = "python mdserv.py %s" % i
			os.system(cmd)
			os.remove(i)
			os._exit(1)
		else:
			pids = (os.getpid(), newpid)
			mdlib.log("* parent: %d, child: %d" % pids)

def generate_medscript(filename):
	#
	ori_xml = ET.parse(filename)
	input = ori_xml.findall('app/input')
	root = ori_xml.find('app')

	for i in input:
		root.remove(i)
	
	ret_val = []
	x = 0

	for i in input:
		x = x + 1
		tree = copy.deepcopy(ori_xml)
		test = tree.find('app')
		for j in range(len(i)):
			test.insert(0, i[len(i) - j - 1])	
		fname ="program/"+ "%s_%s.xml" % (str(int(time.time())), str(int(random.random()*10000)))
		tree.write(fname)
		ret_val.append(fname)

	os.system("rm %s" % filename)

	return ret_val

def process_file(in_file):
	#
	global CONN, soc
	pair = in_file.popitem()

	mdlib.log("* pair: " + pair[1][0] + ", " + pair[0])

	if pair[0] == "medusa_rss":
		info = pair[1][0].split(',')
		pid = info[1]
		qid = info[2]

		mdlib.log("* pid=%s qid=%s" % (str(pid),str(qid)))

		if CONN.has_key(pid):
			mdlib.msg_send(CONN[(pid)], pair[1][0])
	else:
		t_filename = "%s%s" % (str(int(random.random()*10000)), pair[0])
		prognames = generate_medscript(t_filename)
		run_medscript(prognames)


if __name__ == '__main__':
	# initialization
	t = MedTTEventRelay()
	t.start()

	server_class = BaseHTTPServer.HTTPServer
	httpd = server_class((HOSTNAME, NPORT), MedTTCbHandler)

	mdlib.log("* starting medscript_acceptor - %s:%s" % (HOSTNAME, NPORT))

	# event-loop.
	httpd.serve_forever()

	# interrupted.
	for i in CONN:
		CONN[i].close()
	
	httpd.server_close()
	mdlib.log("* stopping medscript_acceptor - %s:%s" % (HOSTNAME, NPORT))
